ImaginaryCTF Jumprope Write Up
Details:
Jeopardy style CTF
Category: Reverse Engineering
Points: 200
Comments:
CENSORED and CENSORED Sitting in a tree, H-A-C-K-I-N-G! First comes pwn, Then comes rev, Then comes a flag And a happy dev!
Write up:
Opening the main function I saw:
int __cdecl main(int argc, const char **argv, const char **envp)
{
puts("Ice cream!");
puts("Soda Pop!");
puts("Cherry on top!");
puts("Is your flag exact?");
puts("Well, let's find out!");
sleep(1u);
puts("\nEighty-eight characters!");
puts("A secret well kept!");
puts("If you get it right,");
puts("I'll shout CORRECT!\n");
if ( !(unsigned int)checkFlag("I'll shout CORRECT!\n", argv) )
printf("Nope!");
return 0;
}
I then looked into the checkFlag function and saw:
__int64 checkFlag()
{
char vars0[8];
void *retaddr;
printf(">>> ");
__isoc99_scanf("%88s%c", &retaddr, &dead);
for ( count = 8; count <= 95; ++count )
{
val = next(val);
vars0[count] ^= x[count - 8] ^ val;
}
return 0LL;
}
From here I can see that the code reads our input and then we xor that data with some other xor'ed data.
From here I extracted the next function:
unsigned __int64 __fastcall next(unsigned __int64 a1)
{
int j;
unsigned __int64 v4;
__int64 v5;
int i;
for ( i = 0; i <= 7; ++i )
{
v5 = 0LL;
v4 = a1;
for ( j = 0; j <= 7; ++j )
{
if ( (unsigned int)test((unsigned int)(j + 1)) )
v5 ^= v4 & 1;
v4 >>= 1;
}
a1 = (v5 << 7) + (a1 >> 1);
}
return a1;
}
The test function:
__int64 __fastcall test(int a1)
{
int i; // [rsp+10h] [rbp-4h]
if ( a1 == 1 )
return 0LL;
for ( i = 2; i < a1 - 1; ++i )
{
if ( !(a1 % i) )
return 0LL;
}
return 1LL;
}
And the x array:
[0x00000000000000FD, 0x000000000000003C, 0x00000000000000C4, 0x000000000000000E, 0x0000000000000076, 0x00000000000000FF, 0x000000000000004B, 0x0000000000000045, 0x000000000000001F, 0x0000000000000040, 0x00000000000000F4, 0x00000000000000E6, 0x0000000000000080, 0x00000000000000B8, 0x00000000000000B5, 0x00000000000000E8, 0x0000000000000076, 0x000000000000008E, 0x000000000000003B, 0x00000000000000F8, 0x00000000000000E4, 0x00000000000000BD, 0x00000000000000C9, 0x00000000000000C7, 0x000000000000003F, 0x00000000000000E6, 0x00000000000000CF, 0x0000000000000015, 0x0000000000000094, 0x000000000000009A, 0x000000000000008A, 0x0000000000000028, 0x000000000000004E, 0x000000000000005E, 0x000000000000001E, 0x000000000000003F, 0x0000000000000025, 0x00000000000000D4, 0x000000000000002C, 0x00000000000000A9, 0x0000000000000036, 0x0000000000000028, 0x0000000000000042, 0x0000000000000040, 0x0000000000000093, 0x000000000000008D, 0x000000000000000F, 0x00000000000000FF, 0x00000000000000AE, 0x000000000000002B, 0x000000000000002B, 0x00000000000000DF, 0x000000000000007E, 0x000000000000001A, 0x000000000000004E, 0x0000000000000005, 0x0000000000000063, 0x00000000000000D0, 0x0000000000000088, 0x00000000000000E1, 0x00000000000000A1, 0x000000000000001F, 0x000000000000005A, 0x000000000000003D, 0x0000000000000036, 0x000000000000004F, 0x00000000000000AE, 0x0000000000000089, 0x000000000000007B, 0x00000000000000D7, 0x0000000000000027, 0x00000000000000D0, 0x0000000000000029, 0x00000000000000C0, 0x000000000000009E, 0x00000000000000F0, 0x0000000000000020, 0x00000000000000DF, 0x0000000000000069, 0x0000000000000077, 0x0000000000000094, 0x00000000000000E9, 0x0000000000000058, 0x000000000000000F, 0x00000000000000B8, 0x00000000000000EC, 0x00000000000000F9, 0x0000000000000024]
I then made a python script to find everything but the input key:
x = [0x00000000000000FD, 0x000000000000003C, 0x00000000000000C4, 0x000000000000000E, 0x0000000000000076, 0x00000000000000FF, 0x000000000000004B, 0x0000000000000045, 0x000000000000001F, 0x0000000000000040, 0x00000000000000F4, 0x00000000000000E6, 0x0000000000000080, 0x00000000000000B8, 0x00000000000000B5, 0x00000000000000E8, 0x0000000000000076, 0x000000000000008E, 0x000000000000003B, 0x00000000000000F8, 0x00000000000000E4, 0x00000000000000BD, 0x00000000000000C9, 0x00000000000000C7, 0x000000000000003F, 0x00000000000000E6, 0x00000000000000CF, 0x0000000000000015, 0x0000000000000094, 0x000000000000009A, 0x000000000000008A, 0x0000000000000028, 0x000000000000004E, 0x000000000000005E, 0x000000000000001E, 0x000000000000003F, 0x0000000000000025, 0x00000000000000D4, 0x000000000000002C, 0x00000000000000A9, 0x0000000000000036, 0x0000000000000028, 0x0000000000000042, 0x0000000000000040, 0x0000000000000093, 0x000000000000008D, 0x000000000000000F, 0x00000000000000FF, 0x00000000000000AE, 0x000000000000002B, 0x000000000000002B, 0x00000000000000DF, 0x000000000000007E, 0x000000000000001A, 0x000000000000004E, 0x0000000000000005, 0x0000000000000063, 0x00000000000000D0, 0x0000000000000088, 0x00000000000000E1, 0x00000000000000A1, 0x000000000000001F, 0x000000000000005A, 0x000000000000003D, 0x0000000000000036, 0x000000000000004F, 0x00000000000000AE, 0x0000000000000089, 0x000000000000007B, 0x00000000000000D7, 0x0000000000000027, 0x00000000000000D0, 0x0000000000000029, 0x00000000000000C0, 0x000000000000009E, 0x00000000000000F0, 0x0000000000000020, 0x00000000000000DF, 0x0000000000000069, 0x0000000000000077, 0x0000000000000094, 0x00000000000000E9, 0x0000000000000058, 0x000000000000000F, 0x00000000000000B8, 0x00000000000000EC, 0x00000000000000F9, 0x0000000000000024]
val = 2
def test(b):
if b == 1:
return 0
for i in range(2, b-1):
if not (b%i):
return 0
return 1
def next(a):
for i in range(0, 8):
v5 = 0
v4 = a
for j in range(0, 8):
if test(j+1):
v5 ^= v4 & 1
v4 >>= 1
a = (v5 << 7) + (a >> 1)
return a
def printA(s):
n = ""
for i in s:
n+=i
print(n)
s = []
for i in range(8, 96):
val = next(val)
s.append(chr(x[i-8] ^ val))
printA(s)
This then output:
xq4f{n0tÔx!st_ni´¨CLbut_Zz%_nigh/M"ef0ref7enty_"5r_haczw2s_camîK!_kn0c¥Ã¹_at_økd00r}
From here it was a mix or bruteforcing a guessing but we were able to find that the flag was:
ictf{n0t_last_night_but_the_night_bef0re_twenty_f0ur_hackers_came_a_kn0cking_at_my_d00r}